#include <string>
#include <iostream>
#include <cmath> 
#include <ctime>

// For terminal delay
#include <chrono>
#include <thread>

#include <fstream>
#include <algorithm> 

#include "doubles.h"

// 简单的延迟函数
void simpleDelay(int milliseconds) {
    clock_t start = clock();
    while (clock() < start + milliseconds * CLOCKS_PER_SEC / 1000) {
        // 空循环
    }
}

doubleGame::doubleGame()
{
    // 使用默认设置（鏖战关闭）
    this->mFinalFightEnabled = false;
    
    // Separate the screen to three windows
    this->mWindows.resize(3);
    initscr();
    // If there wasn't any key pressed don't wait for keypress
    nodelay(stdscr, true);
    // Turn on keypad control
    keypad(stdscr, true);
    // No echo for the key pressed
    noecho();
    // No cursor show
    curs_set(0);
    // Get screen and board parameters
    getmaxyx(stdscr, this->mScreenHeight, this->mScreenWidth);
    this->mGameBoardWidth = this->mScreenWidth - this->mInstructionWidth;
    this->mGameBoardHeight = this->mScreenHeight - this->mInformationHeight;

    this->createInformationBoard();
    this->createGameBoard();
    this->createInstructionBoard();

    mFoodCounter = 0;
    mSpecialFoodActive = false;
    mSpecialFoodTimer = 0;
    mBlinkCounter = 0;
    mSpecialFoodBlink = false;
    mIsReversed1 = false;
    mIsReversed2 = false;
    mReverseTimer1 = 0;
    mReverseTimer2 = 0;

    // 初始化鏖战相关变量
    mIsFinalFight = false;
    mFinalFightTriggered = false;
    mGameStartFrame = 0;
    mFinalFightDisplayCounter = 0;

    mReverseBlinkState1 = false;
    mReverseBlinkState2 = false;
    mReverseBlinkTimer1 = 0;
    mReverseBlinkTimer2 = 0;
}

doubleGame::doubleGame(bool enableFinalFight)
{
    // 使用指定的鏖战设置
    this->mFinalFightEnabled = enableFinalFight;
    
    // Separate the screen to three windows
    this->mWindows.resize(3);
    initscr();
    // If there wasn't any key pressed don't wait for keypress
    nodelay(stdscr, true);
    // Turn on keypad control
    keypad(stdscr, true);
    // No echo for the key pressed
    noecho();
    // No cursor show
    curs_set(0);
    // Get screen and board parameters
    getmaxyx(stdscr, this->mScreenHeight, this->mScreenWidth);
    this->mGameBoardWidth = this->mScreenWidth - this->mInstructionWidth;
    this->mGameBoardHeight = this->mScreenHeight - this->mInformationHeight;

    this->createInformationBoard();
    this->createGameBoard();
    this->createInstructionBoard();

    mFoodCounter = 0;
    mSpecialFoodActive = false;
    mSpecialFoodTimer = 0;
    mBlinkCounter = 0;
    mSpecialFoodBlink = false;
    mIsReversed1 = false;
    mIsReversed2 = false;
    mReverseTimer1 = 0;
    mReverseTimer2 = 0;

    // 初始化鏖战相关变量
    mIsFinalFight = false;
    mFinalFightTriggered = false;
    mGameStartFrame = 0;
    mFinalFightDisplayCounter = 0;
    
    // 初始化技能相关变量
    mPlayer1LastDropFrame = -1;
    mPlayer2LastDropFrame = -1;

    mSnakeController = std::make_unique<SnakeController>();

    // Initialize the leader board to be all zeros
    this->mLeaderBoard.assign(this->mNumLeaders, 0);
    this->mBoostDelay = this->mBaseDelay / 2;

    mReverseBlinkState1 = false;
    mReverseBlinkState2 = false;
    mReverseBlinkTimer1 = 0;
    mReverseBlinkTimer2 = 0;
}

doubleGame::~doubleGame()
{
    for (int i = 0; i < this->mWindows.size(); i ++)
    {
        delwin(this->mWindows[i]);
    }
    endwin();
}

void doubleGame::createInformationBoard()
{
    int startY = 0;
    int startX = 0;
    this->mWindows[0] = newwin(this->mInformationHeight, this->mScreenWidth, startY, startX);
}

void doubleGame::renderInformationBoard() const
{
    mvwprintw(this->mWindows[0], 1, 1, "Welcome to The Snake Game!");
    mvwprintw(this->mWindows[0], 2, 1, "Authors: Jiang Yiyang, Mei Zhaoguo, Wang Lianwen");
    mvwprintw(this->mWindows[0], 3, 1, "Website: https://gitee.com/jyy16/snakegame");
    mvwprintw(this->mWindows[0], 4, 1, "Implemented using C++ and libncurses library.");
    wrefresh(this->mWindows[0]);
}

void doubleGame::createGameBoard()
{
    int startY = this->mInformationHeight;
    int startX = 0;
    this->mWindows[1] = newwin(this->mScreenHeight - this->mInformationHeight, this->mScreenWidth - this->mInstructionWidth, startY, startX);
}

void doubleGame::renderGameBoard() const
{
    wrefresh(this->mWindows[1]);
}

void doubleGame::createInstructionBoard()
{
    int startY = this->mInformationHeight;
    int startX = this->mScreenWidth - this->mInstructionWidth;
    this->mWindows[2] = newwin(this->mScreenHeight - this->mInformationHeight, this->mInstructionWidth, startY, startX);
}

void doubleGame::renderInstructionBoard() const
{
    mvwprintw(this->mWindows[2], 1, 1, "Manual");

    mvwprintw(this->mWindows[2], 3, 1, "Up:    W  I");
    mvwprintw(this->mWindows[2], 4, 1, "Down:  S  K");
    mvwprintw(this->mWindows[2], 5, 1, "Left:  A  J");
    mvwprintw(this->mWindows[2], 6, 1, "Right: D  L");
    mvwprintw(this->mWindows[2], 7, 1, "Drop:  E  O");
    mvwprintw(this->mWindows[2], 8, 1, "Pause: P");

    mvwprintw(this->mWindows[2], 10, 1, "Difficulty");
    mvwprintw(this->mWindows[2], 13, 1, "Points");
    mvwprintw(this->mWindows[2], 16, 1, "Boost");
    
    // 显示鏖战模式状态
    if (this->mFinalFightEnabled)
    {
        mvwprintw(this->mWindows[2], 23, 1, "Final Fight: ON!");
    }
    else
    {
        mvwprintw(this->mWindows[2], 23, 1, "Final Fight: OFF!");
    }

    wrefresh(this->mWindows[2]);
}


void doubleGame::renderLeaderBoard() const
{
    // If there is not too much space, skip rendering the leader board 
    if (this->mScreenHeight - this->mInformationHeight - 14 - 2 < 3 * 2)
    {
        return;
    }
    mvwprintw(this->mWindows[2], 16, 1, "Leader Board");
    std::string pointString;
    std::string rank;
    for (int i = 0; i < std::min(this->mNumLeaders, this->mScreenHeight - this->mInformationHeight - 14 - 2); i ++)
    {
        pointString = std::to_string(this->mLeaderBoard[i]);
        rank = "#" + std::to_string(i + 1) + ":";
        mvwprintw(this->mWindows[2], 16 + (i + 1), 1, rank.c_str());
        mvwprintw(this->mWindows[2], 16 + (i + 1), 5, pointString.c_str());
    }
    wrefresh(this->mWindows[2]);
}

bool doubleGame::renderRestartMenu() const
{
    WINDOW * menu;
    int width = this->mGameBoardWidth * 0.6;
    int height = this->mGameBoardHeight * 0.5;
    int startX = this->mGameBoardWidth * 0.2;
    int startY = this->mGameBoardHeight * 0.25 + this->mInformationHeight;

    menu = newwin(height, width, startY, startX);
    box(menu, 0, 0);
    std::vector<std::string> menuItems = {"Restart", "Quit"};

    int index = 0;
    int offset = 6;
    
    // Display game result
    mvwprintw(menu, 1, 1, "Game Over!");
    switch(this->mGameResult)
    {
        case GameResult::PLAYER1_WIN:
            mvwprintw(menu, 2, 1, "Player 1 Wins!");
            break;
        case GameResult::PLAYER2_WIN:
            mvwprintw(menu, 2, 1, "Player 2 Wins!");
            break;
        case GameResult::DRAW:
            mvwprintw(menu, 2, 1, "Draw!");
            break;
        default:
            break;
    }
    
    // Display scores
    std::string player1Score = "Player 1: " + std::to_string(this->mPoints1 + this->mBonusPoints1);
    std::string player2Score = "Player 2: " + std::to_string(this->mPoints2 + this->mBonusPoints2);
    mvwprintw(menu, 3, 1, player1Score.c_str());
    mvwprintw(menu, 4, 1, player2Score.c_str());
    
    // Rest of the menu logic remains the same...
    wattron(menu, A_STANDOUT);
    mvwprintw(menu, 0 + offset, 1, menuItems[0].c_str());
    wattroff(menu, A_STANDOUT);
    mvwprintw(menu, 1 + offset, 1, menuItems[1].c_str());

    wrefresh(menu);
    
    // Menu input handling (same as before)
    int key;
    while (true)
    {
        key = getch();
        switch(key)
        {
            case 'W':
            case 'w':
            case KEY_UP:
            {
                mvwprintw(menu, index + offset, 1, menuItems[index].c_str());
                index--;
                index = (index < 0) ? menuItems.size() - 1 : index;
                wattron(menu, A_STANDOUT);
                mvwprintw(menu, index + offset, 1, menuItems[index].c_str());
                wattroff(menu, A_STANDOUT);
                break;
            }
            case 'S':
            case 's':
            case KEY_DOWN:
            {
                mvwprintw(menu, index + offset, 1, menuItems[index].c_str());
                index++;
                index = (index > menuItems.size() - 1) ? 0 : index;
                wattron(menu, A_STANDOUT);
                mvwprintw(menu, index + offset, 1, menuItems[index].c_str());
                wattroff(menu, A_STANDOUT);
                break;
            }
        }
        wrefresh(menu);
        if (key == ' ' || key == 10)
        {
            break;
        }
        simpleDelay(100);
    }
    delwin(menu);

    if (index == 0)
    {
        return true;
    }
    else
    {
        return false;
    }
}

void doubleGame::renderPoints() const
{
    std::string pointString = "P1: " + std::to_string(this->mPoints1) + " + " + std::to_string(this->mBonusPoints1);
    mvwprintw(this->mWindows[2], 13, 1, pointString.c_str());
    pointString = "P2: " + std::to_string(this->mPoints2) + " + " + std::to_string(this->mBonusPoints2);
    mvwprintw(this->mWindows[2], 14, 1, pointString.c_str());
    wrefresh(this->mWindows[2]);
}

void doubleGame::renderBoost() const
{
    std::string P1Boost = "Player1 Boost!";
    std::string P2Boost = "Player2 Boost!";
    if (this->mBoost1) 
    {
        mvwprintw(this->mWindows[2], 21, 1, P1Boost.c_str());
    } else {
        mvwprintw(this->mWindows[2], 21, 1, "                ");
    }
    if (this->mBoost2)
    {
        mvwprintw(this->mWindows[2], 22, 1, P2Boost.c_str());
    } else {
        mvwprintw(this->mWindows[2], 22, 1, "                ");
    }

    wrefresh(this->mWindows[2]);
}

void doubleGame::renderReverse() const
{
    if (this->mIsReversed2) 
    {
        mvwprintw(this->mWindows[2], 3, 1, "Up:    W  K");
        mvwprintw(this->mWindows[2], 4, 1, "Down:  S  I");
        mvwprintw(this->mWindows[2], 5, 1, "Left:  A  L");
        mvwprintw(this->mWindows[2], 6, 1, "Right: D  J");
    } 
    else if (this->mIsReversed1)
    {
        mvwprintw(this->mWindows[2], 3, 1, "Up:    S  I");
        mvwprintw(this->mWindows[2], 4, 1, "Down:  W  K");
        mvwprintw(this->mWindows[2], 5, 1, "Left:  D  J");
        mvwprintw(this->mWindows[2], 6, 1, "Right: A  L");
    }
    else
    {
        mvwprintw(this->mWindows[2], 3, 1, "Up:    W  I");
        mvwprintw(this->mWindows[2], 4, 1, "Down:  S  K");
        mvwprintw(this->mWindows[2], 5, 1, "Left:  A  J");
        mvwprintw(this->mWindows[2], 6, 1, "Right: D  L");
    }

    wrefresh(this->mWindows[2]);
}

void doubleGame::renderDifficulty() const
{
    std::string difficultyString = std::to_string(this->mDifficulty);
    mvwprintw(this->mWindows[2], 11, 1, difficultyString.c_str());
    wrefresh(this->mWindows[2]);
}

void doubleGame::renderTime()
{
    mvwprintw(this->mWindows[2], 25, 1, "Time: %d", 45 - this->trueTotalFrames / 20);
    wrefresh(this->mWindows[2]);
}

void doubleGame::initializeGame()
{
    // Initialize Player 1 snake (starts from left side)
    this->mPtrSnake1.reset(new Snake(this->mGameBoardWidth, this->mGameBoardHeight, this->mInitialSnakeLength));
    // Set Player 1 starting position (left side)
    this->mPtrSnake1->setPosition(3, this->mGameBoardHeight / 2);
    this->mPtrSnake1->setDirection(Direction::Right);
    
    // Initialize Player 2 snake (starts from right side)
    this->mPtrSnake2.reset(new Snake(this->mGameBoardWidth, this->mGameBoardHeight, this->mInitialSnakeLength));
    // Set Player 2 starting position (right side)
    this->mPtrSnake2->setPosition(this->mGameBoardWidth - 4, this->mGameBoardHeight / 2);
    this->mPtrSnake2->setDirection(Direction::Left);
    
    this->createRamdonFood();
    this->mPtrSnake1->senseFood(this->mFood);
    this->mPtrSnake2->senseFood(this->mFood);
    
    this->mDifficulty = 0;
    this->mPoints1 = 0;
    this->mPoints2 = 0;
    this->mBonusPoints1 = 0;
    this->mBonusPoints2 = 0;
    this->mGameResult = GameResult::ONGOING;
    this->mDelay = this->mBaseDelay;
    this->mBoost1 = false;
    this->mBoost2 = false;
    this->mMoveCounter = 0;
    this->mSpecialFoodActive = false;
    this->mSpecialFoodTimer = 0;
    this->mBlinkCounter = 0;
    this->mSpecialFoodBlink = false;
    this->mIsReversed1 = false;
    this->mIsReversed2 = false;
    this->mReverseTimer1 = 0;
    this->mReverseTimer2 = 0;
    this->mFoodCounter = 0;
    this->trueTotalFrames = 0;
    mReverseBlinkState1 = false;
    mReverseBlinkState2 = false;
    mReverseBlinkTimer1 = 0;
    mReverseBlinkTimer2 = 0;

    //重置技能
    this->mFrameCounter = 0;
    this->mTemporaryObstacles.clear(); // 清空上一局留下的障碍物
    this->mPlayer1LastDropFrame = 0;
    this->mPlayer2LastDropFrame = 0;
    // 重置技能状态
    this->mPlayer1SkillActive = false;
    this->mPlayer2SkillActive = false;

    this->maxDrop1 = -1;
    this->maxDrop2 = -1;

    this->mPlayer1BufferedDirection.reset(); // 重置缓冲方向
    this->mPlayer2BufferedDirection.reset(); // 重置缓冲方向
    // 重置鏖战相关状态
    this->mIsFinalFight = false;
    this->mFinalFightTriggered = false;
    this->mGameStartFrame = 0;
    this->mFinalFightDisplayCounter = 0;
}

void doubleGame::createRamdonFood()
{
    std::vector<SnakeBody> availableGrids;
    for (int i = 1; i < this->mGameBoardHeight - 1; i ++)
    {
        for (int j = 1; j < this->mGameBoardWidth - 1; j ++)
        {
            if(this->mPtrSnake1->isPartOfSnake(j, i) || this->mPtrSnake2->isPartOfSnake(j, i))
            {
                continue;
            }
            
            bool isObstaclePosition = std::any_of(mTemporaryObstacles.begin(), mTemporaryObstacles.end(),
                [j, i](const TemporaryObstacle& obs) {
                    return obs.position.getX() == j && obs.position.getY() == i;
                });
            
            if (!isObstaclePosition)
            {
                availableGrids.push_back(SnakeBody(j, i));
            }
        }
    }

    // Randomly select a grid that is not occupied by the snake
    int random_idx = std::rand() % availableGrids.size();
    this->mFood = availableGrids[random_idx];

    //Randomly decide whether to give bonus direction
    float randomFloat = static_cast<float>(std::rand()) / (float)RAND_MAX;
    if (randomFloat < this->mBonusProbability) 
    {
        int foodX = this->mFood.getX();
        int foodY = this->mFood.getY();

        std::vector<Direction> availableDirections;

        if (foodX > 1)
        {
            availableDirections.push_back(Direction::Right);
        }
        if (foodX < this->mGameBoardWidth - 2)
        {
            availableDirections.push_back(Direction::Left);
        }
        if (foodY > 1)
        {
            availableDirections.push_back(Direction::Down);
        }
        if (foodY < this->mGameBoardHeight - 2)
        {
            availableDirections.push_back(Direction::Up);
        }

        if (!availableDirections.empty())
        {
            int randomDirectionIdx = std::rand() % availableDirections.size();
            Direction randomDirection = availableDirections[randomDirectionIdx];
            this->mFood.setBonusDirection(randomDirection);
        }
    }

    mFoodCounter++;

    if (mFoodCounter >= mSpecialFoodInterval && !mSpecialFoodActive)
    {
        createSpecialFood();
        mFoodCounter = 0;
    }
}

void doubleGame::createSpecialFood()
{
    std::vector<SnakeBody> availableGrids;
    
    // 找到所有可用的网格位置
    for (int i = 1; i < this->mGameBoardWidth - 1; ++i)
    {
        for (int j = 1; j < this->mGameBoardHeight - 1; ++j)
        {
            SnakeBody grid(i, j);
            // 确保不与蛇身、普通食物、临时障碍物重叠
            if (!this->mPtrSnake1->isPartOfSnake(i, j) && 
                !this->mPtrSnake2->isPartOfSnake(i, j) &&
                !(mFood.getX() == i && mFood.getY() == j))
            {
                bool isObstacle = false;
                for (const auto& obs : mTemporaryObstacles)
                {
                    if (obs.position.getX() == i && obs.position.getY() == j)
                    {
                        isObstacle = true;
                        break;
                    }
                }
                if (!isObstacle)
                {
                    availableGrids.push_back(grid);
                }
            }
        }
    }
    
    if (!availableGrids.empty())
    {
        int random_idx = rand() % availableGrids.size();
        mSpecialFood = availableGrids[random_idx];
        mSpecialFoodActive = true;
        mSpecialFoodTimer = mSpecialFoodLifetime;
        mBlinkCounter = 0;
        mSpecialFoodBlink = true;
    }
}

void doubleGame::updateSpecialFood()
{
    if (mSpecialFoodActive)
    {
        mSpecialFoodTimer--;
        mBlinkCounter++;
        
        // 处理闪烁效果
        if (mBlinkCounter >= mBlinkInterval)
        {
            mSpecialFoodBlink = !mSpecialFoodBlink;
            mBlinkCounter = 0;
        }
        
        // 检查是否超时
        if (mSpecialFoodTimer <= 0)
        {
            mSpecialFoodActive = false;
        }
    }
}

// 渲染特种食物
void doubleGame::renderSpecialFood() const
{
    if (mSpecialFoodActive && mSpecialFoodBlink)
    {
        // 使用不同的颜色或属性来突出显示特种食物
        wattron(this->mWindows[1], A_BOLD | A_BLINK);
        mvwaddch(this->mWindows[1], mSpecialFood.getY(), mSpecialFood.getX(), mSpecialFoodSymbol);
        wattroff(this->mWindows[1], A_BOLD | A_BLINK);
    }
}

// 检查特种食物碰撞
void doubleGame::checkSpecialFoodCollision()
{
    if (!mSpecialFoodActive) return;
    
    SnakeBody snake1Head = mPtrSnake1->getHead();
    SnakeBody snake2Head = mPtrSnake2->getHead();
    
    // 检查玩家1是否吃到特种食物
    if (snake1Head.getX() == mSpecialFood.getX() && snake1Head.getY() == mSpecialFood.getY())
    {
        // 玩家1吃到特种食物，玩家2被反向控制
        mIsReversed2 = true;
        mReverseTimer2 = mReverseDuration;
        // 添加闪烁效果
        mReverseBlinkState2 = true;
        mReverseBlinkTimer2 = mReverseBlinkDuration;
        mSpecialFoodActive = false;
    }
    // 检查玩家2是否吃到特种食物
    else if (snake2Head.getX() == mSpecialFood.getX() && snake2Head.getY() == mSpecialFood.getY())
    {
        // 玩家2吃到特种食物，玩家1被反向控制
        mIsReversed1 = true;
        mReverseTimer1 = mReverseDuration;
        // 添加闪烁效果
        mReverseBlinkState1 = true;
        mReverseBlinkTimer1 = mReverseBlinkDuration;
        mSpecialFoodActive = false;
    }
}

// 更新反向控制状态
void doubleGame::updateReverseStates()
{
    if (mIsReversed1)
    {
        mReverseTimer1--;
        if (mReverseTimer1 <= 0)
        {
            mIsReversed1 = false;
            // 反向控制结束时也触发闪烁效果
            mReverseBlinkState1 = true;
            mReverseBlinkTimer1 = mReverseBlinkDuration;
        }
    }
    
    if (mIsReversed2)
    {
        mReverseTimer2--;
        if (mReverseTimer2 <= 0)
        {
            mIsReversed2 = false;
            // 反向控制结束时也触发闪烁效果
            mReverseBlinkState2 = true;
            mReverseBlinkTimer2 = mReverseBlinkDuration;
        }
    }

    // 更新闪烁状态
    if (mReverseBlinkState1)
    {
        mReverseBlinkTimer1--;
        if (mReverseBlinkTimer1 <= 0)
        {
            mReverseBlinkState1 = false;
        }
    }
    
    if (mReverseBlinkState2)
    {
        mReverseBlinkTimer2--;
        if (mReverseBlinkTimer2 <= 0)
        {
            mReverseBlinkState2 = false;
        }
    }
}

void doubleGame::renderFood() const
{
    //Bonus direction
    char foodSymbol = this->mFood.hasBonusDirection() ? '*' : this->mFoodSymbol;
    mvwaddch(this->mWindows[1], this->mFood.getY(), this->mFood.getX(), foodSymbol);

    if (this->mFood.hasBonusDirection())
    {
        char directionSymbol;
        int offsetX = 0;
        int offsetY = 0;
        switch (this->mFood.getBonusDirection())
        {
            case Direction::Up:
            {
                directionSymbol = '^';
                offsetY = 1;
                break;
            }
            case Direction::Down:
            {
                directionSymbol = 'v';
                offsetY = -1;
                break;      
            }
            case Direction::Left:
            {
                directionSymbol = '<';
                offsetX = 1;
                break;
            }
            case Direction::Right:
            {
                directionSymbol = '>';
                offsetX = -1;
                break;
            }
        }

        mvwaddch(this->mWindows[1], this->mFood.getY() + offsetY, this->mFood.getX() + offsetX, directionSymbol);
    }

    //wrefresh(this->mWindows[1]);  统一刷新
}

void doubleGame::renderSnakes() const
{
    // Render Player 1 snake
    std::vector<SnakeBody> snake1_body = this->mPtrSnake1->getSnake();
    // 检查玩家1是否需要闪烁
    bool shouldBlinkPlayer1 = mReverseBlinkState1 && ((mReverseBlinkTimer1 / mBlinkFrequency) % 2 == 0);
    for (auto& body : snake1_body)
    {
        if (shouldBlinkPlayer1)
        {
            // 闪烁效果：使用反色显示
            wattron(this->mWindows[1], A_REVERSE);
            mvwaddch(this->mWindows[1], body.getY(), body.getX(), this->mSnakeSymbol_1);
            wattroff(this->mWindows[1], A_REVERSE);
        }
        else
        {
            mvwaddch(this->mWindows[1], body.getY(), body.getX(), this->mSnakeSymbol_1);
        }
    }
    
    // Render Player 2 snake
    std::vector<SnakeBody> snake2_body = this->mPtrSnake2->getSnake();
    // 检查玩家2是否需要闪烁
    bool shouldBlinkPlayer2 = mReverseBlinkState2 && ((mReverseBlinkTimer2 / mBlinkFrequency) % 2 == 0);
    for (auto& body : snake2_body)
    {
        if (shouldBlinkPlayer2)
        {
            // 闪烁效果：使用反色显示
            wattron(this->mWindows[1], A_REVERSE);
            mvwaddch(this->mWindows[1], body.getY(), body.getX(), this->mSnakeSymbol_2);
            wattroff(this->mWindows[1], A_REVERSE);
        }
        else
        {
            mvwaddch(this->mWindows[1], body.getY(), body.getX(), this->mSnakeSymbol_2);
        }
    }
}

GameResult doubleGame::checkCollisions()
{
    // Check wall collisions
    bool snake1_wall_collision = this->mPtrSnake1->checkCollision();
    bool snake2_wall_collision = this->mPtrSnake2->checkCollision();
    
    // Get head positions
    SnakeBody snake1_head = this->mPtrSnake1->getHead();
    SnakeBody snake2_head = this->mPtrSnake2->getHead();
    
    // Check head-to-head collision
    bool head_collision = (snake1_head.getX() == snake2_head.getX() && 
                          snake1_head.getY() == snake2_head.getY());
    
    // Check if snake1 head hits snake2 body
    bool snake1_hits_snake2 = this->mPtrSnake2->isPartOfSnake(snake1_head.getX(), snake1_head.getY());
    
    // Check if snake2 head hits snake1 body
    bool snake2_hits_snake1 = this->mPtrSnake1->isPartOfSnake(snake2_head.getX(), snake2_head.getY());
    
    for (const auto& obs : mTemporaryObstacles)
    {
        if (snake1_head == obs.position) {
            // Player 1 临时障碍物，Player 2 胜利
            return GameResult::PLAYER2_WIN;
        }
        if (snake2_head == obs.position) {
            // Player 2 临时障碍物，Player 1 胜利
            return GameResult::PLAYER1_WIN;
        }
    }

    // Determine game result
    if (head_collision) {
        return GameResult::DRAW;
    }
    
    if ((snake1_wall_collision || snake1_hits_snake2) && 
        (snake2_wall_collision || snake2_hits_snake1)) {
        return GameResult::DRAW;
    }
    
    if (snake1_wall_collision || snake1_hits_snake2) {
        return GameResult::PLAYER2_WIN;
    }
    
    if (snake2_wall_collision || snake2_hits_snake1) {
        return GameResult::PLAYER1_WIN;
    }
    
    return GameResult::ONGOING;
}

void doubleGame::renderBoards() const
{
    for (int i = 0; i < this->mWindows.size(); i ++)
    {
        werase(this->mWindows[i]);
    }
    this->renderInformationBoard();
    this->renderGameBoard();
    this->renderInstructionBoard();
    for (int i = 0; i < this->mWindows.size(); i ++)
    {
        box(this->mWindows[i], 0, 0);
        wrefresh(this->mWindows[i]);
    }
    this->renderLeaderBoard();
}


void doubleGame::adjustDelay()
{
    int maxPoints = std::max(this->mPoints1, this->mPoints2);
    this->mDifficulty = maxPoints / 5;
    if (maxPoints % 5 == 0)
    {
        this->mDelay = this->mBaseDelay * pow(0.75, this->mDifficulty);
    }
}

void doubleGame::renderSkill()
{
    if (this->trueTotalFrames - this->mPlayer1LastDropFrame >= this->mSkillCooldownFrames)
    {
        // 检查技能是否可用
        if (!this->mPlayer1SkillActive)
        {
            mvwprintw(this->mWindows[2], 27, 1, "P1 Skill Ready");
        }
    } 
    else
    {
        mvwprintw(this->mWindows[2], 27, 1,     "P1 Cooling    ");
    }

    if (this->trueTotalFrames - this->mPlayer2LastDropFrame >= this->mSkillCooldownFrames)
    {
        // 检查技能是否可用
        if (!this->mPlayer2SkillActive)
        {
            mvwprintw(this->mWindows[2], 28, 1, "P2 Skill Ready");
        }
    }
    else
    {
        mvwprintw(this->mWindows[2], 28, 1,     "P2 Cooling    ");
    }

    wrefresh(this->mWindows[2]);
}

void doubleGame::runGame()
{
    this->mIsPaused = false;  // 重置暂停状态
    this->mGameStartFrame = this->mFrameCounter;  // 记录游戏开始时间
    
    while (this->mGameResult == GameResult::ONGOING)
    {
        this->mFrameCounter++;

        
        // 检查是否进入鏖战
        this->checkFinalFight();
        
        // 如果刚进入鏖战，显示鏖战消息并暂停3秒
        if (this->mIsFinalFight && this->mFinalFightDisplayCounter < this->mFinalFightDisplayDuration)
        {
            this->renderFinalFightMessage();
            this->mFinalFightDisplayCounter++;
            
            // 暂停游戏3秒并闪屏3次
            if (this->mFinalFightDisplayCounter == 1)
            {
                this->renderFinalFightWithFlash();
            }
            
            simpleDelay(50);
            continue;
        }
        
        // 处理输入和暂停
        int controlResult = mSnakeController->controlSnakesWithPause(mPtrSnake1.get(), mPtrSnake2.get(), 
                                                                    mBoost1, mBoost2, mTemporaryObstacles,
                                                                    this->trueTotalFrames, mPlayer1LastDropFrame, this->mSkillCooldownFrames,
                                                                    mPlayer2LastDropFrame, mIsPaused, 
                                                                    mIsReversed1, mIsReversed2, &this->mPlayer1SkillActive, &this->mPlayer2SkillActive);
        
        // 检查是否请求退出
        if (controlResult == 2)
        {
            break;  // 用户在暂停时选择退出
        }
        
        // 如果游戏暂停，跳过游戏逻辑更新
        if (this->mIsPaused)
        {
            int pauseChoice = this->renderPauseMenu();
            if (pauseChoice == 0) 
            {
                this->mIsPaused = false;  // 继续游戏
                this->renderSnakes();
                this->renderFood();
                this->renderSpecialFood();
                this->renderTemporaryObstacles();
                this->renderPoints();
                this->renderBoost();
            }
            else
            {
                break;
            }
            continue;
        }
        
        this->updateTemporaryObstacles();
        updateSpecialFood();
        updateReverseStates();
        checkSpecialFoodCollision();
        
        werase(this->mWindows[1]);
        box(this->mWindows[1], 0, 0);

        this->mMoveCounter++;
        
        bool shouldMoveSnake1 = false;
        bool shouldMoveSnake2 = false;
        
        if (this->mBoost1) {
            shouldMoveSnake1 = true;
        } else {
            shouldMoveSnake1 = (this->mMoveCounter % 2 == 0);
        }
        
        if (this->mBoost2) {
            shouldMoveSnake2 = true;
        } else {
            shouldMoveSnake2 = (this->mMoveCounter % 2 == 0);
        }

        bool willEatBonus1 = false;
        bool willEatBonus2 = false;
        bool eatfood1 = false;
        bool eatfood2 = false;
        
        //玩家1技能断尾
        if (this->mPlayer1SkillActive)
        {
            shouldMoveSnake1 = false;
            SnakeBody droppedPart = this->mPtrSnake1->dropTail(this->maxDrop1);
            if (droppedPart.getX() != -1) // 检查断尾是否成功 (蛇身足够长)
            {
                mTemporaryObstacles.push_back({droppedPart, mFrameCounter});
            }
            else // 如果蛇身太短导致断尾失败
            {
                this->mPlayer1SkillActive = false; // 自动关闭技能开关
            }
        }
        //玩家2技能断尾
        if (this->mPlayer2SkillActive && shouldMoveSnake2)
        {
            shouldMoveSnake2 = false;
            SnakeBody droppedPart = this->mPtrSnake2->dropTail(this->maxDrop2);
            if (droppedPart.getX() != -1)
            {
                mTemporaryObstacles.push_back({droppedPart, mFrameCounter});
            }
            else
            {
                this->mPlayer2SkillActive = false;
            }
        }


        if (shouldMoveSnake1) {
            if (this->mPtrSnake1->touchFood() && this->mFood.hasBonusDirection()) {
                willEatBonus1 = (this->mPtrSnake1->getCurrentDirection() == this->mFood.getBonusDirection());
            }
            eatfood1 = this->mPtrSnake1->moveFoward();
        }
        
        if (shouldMoveSnake2) {
            if (this->mPtrSnake2->touchFood() && this->mFood.hasBonusDirection()) {
                willEatBonus2 = (this->mPtrSnake2->getCurrentDirection() == this->mFood.getBonusDirection());
            }
            eatfood2 = this->mPtrSnake2->moveFoward();
        }
        
        // 检查并执行玩家1的缓冲指令
        if (mPlayer1BufferedDirection.has_value())
        {
            // 尝试执行缓冲的转向指令
            if (mPtrSnake1->changeDirection(mPlayer1BufferedDirection.value()))
            {
                // 如果执行成功，就清空缓冲区
                mPlayer1BufferedDirection.reset();
            }
        }

        // 检查并执行玩家2的缓冲指令
        if (mPlayer2BufferedDirection.has_value())
        {
            if (mPtrSnake2->changeDirection(mPlayer2BufferedDirection.value()))
            {
                mPlayer2BufferedDirection.reset();
            }
        }
        
        this->renderSnakes();
        
        if (eatfood1) {
            this->mPoints1++;
            if (willEatBonus1) {
                this->mBonusPoints1 += this->mBonusScore;
            }
            this->createRamdonFood();
            this->mPtrSnake1->senseFood(this->mFood);
            this->mPtrSnake2->senseFood(this->mFood);
            this->adjustDelay();
        }

        if (eatfood2) {
            this->mPoints2++;
            if (willEatBonus2) {
                this->mBonusPoints2 += this->mBonusScore;
            }
            this->createRamdonFood();
            this->mPtrSnake1->senseFood(this->mFood);
            this->mPtrSnake2->senseFood(this->mFood);
            this->adjustDelay();
        }

        this->renderFood();
        this->renderSpecialFood();
        this->renderTemporaryObstacles();
        wrefresh(this->mWindows[1]);// 统一刷新游戏窗口
        this->renderPoints();
        this->renderDifficulty();
        this->renderBoost();
        this->renderSkill();
        this->renderReverse();

        if (!this->mIsPaused)
        {
            this->trueTotalFrames++;
            if (this->mFinalFightEnabled && !this->mIsFinalFight)
            {
                this->renderTime();
            }
        }

        // 鏖战时速度*3（延迟减少到1/3）
        int currentDelay = this->mBaseDelay / 2;
        if (this->mIsFinalFight)
        {
            currentDelay = currentDelay / 3;
        }
        simpleDelay(currentDelay);

        this->mGameResult = this->checkCollisions();
        
        refresh();
    }
}

void doubleGame::startGame()
{
    refresh();
    bool choice;
    while (true)
    {
        this->readLeaderBoard();
        this->renderBoards();
        this->initializeGame();
        this->runGame();
        this->updateLeaderBoard();
        this->writeLeaderBoard();
        choice = this->renderRestartMenu();
        if (choice == false)
        {
            break;
        }
    }
}

// https://en.cppreference.com/w/cpp/io/basic_fstream
bool doubleGame::readLeaderBoard()
{
    std::fstream fhand(this->mRecordBoardFilePath, fhand.binary | fhand.in);
    if (!fhand.is_open())
    {
        return false;
    }
    int temp;
    int i = 0;
    while ((!fhand.eof()) && (i < mNumLeaders))
    {
        fhand.read(reinterpret_cast<char*>(&temp), sizeof(temp));
        this->mLeaderBoard[i] = temp;
        i ++;
    }
    fhand.close();
    return true;
}

bool doubleGame::updateLeaderBoard()
{
    bool updated = false;
    // Use the higher score between two players for leaderboard
    int score1 = this->mPoints1 + this->mBonusPoints1;
    int score2 = this->mPoints2 + this->mBonusPoints2;

    for (int i = 0; i < this->mNumLeaders; i++)
    {
        if (this->mLeaderBoard[i] >= score1)
        {
            continue;
        }
        int oldScore = this->mLeaderBoard[i];
        this->mLeaderBoard[i] = score1;
        score1 = oldScore;
        updated = true;
    }

    for (int i = 0; i < this->mNumLeaders; i++)
    {
        if (this->mLeaderBoard[i] >= score2)
        {
            continue;
        }
        int oldScore = this->mLeaderBoard[i];
        this->mLeaderBoard[i] = score2;
        score2 = oldScore;
        updated = true;
    }
    return updated;
}

bool doubleGame::writeLeaderBoard()
{
    // trunc: clear the data file
    std::fstream fhand(this->mRecordBoardFilePath, fhand.binary | fhand.trunc | fhand.out);
    if (!fhand.is_open())
    {
        return false;
    }
    for (int i = 0; i < this->mNumLeaders; i ++)
    {
        fhand.write(reinterpret_cast<char*>(&this->mLeaderBoard[i]), sizeof(this->mLeaderBoard[i]));;
    }
    fhand.close();
    return true;
}


// 渲染所有临时障碍物
void doubleGame::renderTemporaryObstacles() const
{
    for (const auto& obs : mTemporaryObstacles)
    {
        // 使用一个独特的字符 'x' 来表示临时障碍物
        mvwaddch(this->mWindows[1], obs.position.getY(), obs.position.getX(), 'x'); 
    }
}

// 更新障碍物状态，移除过期的障碍物
void doubleGame::updateTemporaryObstacles()
{
    mTemporaryObstacles.erase(
        std::remove_if(mTemporaryObstacles.begin(), mTemporaryObstacles.end(),
                       [this](const TemporaryObstacle& obs) {
                           return (this->mFrameCounter - obs.creationFrame) >= OBSTACLE_LIFESPAN_FRAMES;
                       }),
        mTemporaryObstacles.end());
}

// 暂停相关方法实现
void doubleGame::togglePause()
{
    this->mIsPaused = !this->mIsPaused;
}

int doubleGame::renderPauseMenu() const
{
    WINDOW * menu;
    int width = this->mGameBoardWidth * 0.6;
    int height = this->mGameBoardHeight * 0.4;
    int startX = this->mGameBoardWidth * 0.2;
    int startY = this->mGameBoardHeight * 0.3 + this->mInformationHeight;

    menu = newwin(height, width, startY, startX);
    box(menu, 0, 0);
    std::vector<std::string> menuItems = {"Resume", "Quit"};

    int index = 0;
    int offset = 4;
    
    // Display pause title
    mvwprintw(menu, 1, 1, "Game Paused");
    
    // Display current scores
    std::string player1Score = "Player 1: " + std::to_string(this->mPoints1 + this->mBonusPoints1);
    std::string player2Score = "Player 2: " + std::to_string(this->mPoints2 + this->mBonusPoints2);
    mvwprintw(menu, 2, 1, player1Score.c_str());
    mvwprintw(menu, 3, 1, player2Score.c_str());
    
    // Initial menu display
    wattron(menu, A_STANDOUT);
    mvwprintw(menu, 0 + offset, 1, menuItems[0].c_str());
    wattroff(menu, A_STANDOUT);
    mvwprintw(menu, 1 + offset, 1, menuItems[1].c_str());

    wrefresh(menu);
    
    // Menu input handling
    int key;
    while (true)
    {
        key = getch();
        switch(key)
        {
            case 'W':
            case 'w':
            case KEY_UP:
            {
                mvwprintw(menu, index + offset, 1, menuItems[index].c_str());
                index--;
                index = (index < 0) ? menuItems.size() - 1 : index;
                wattron(menu, A_STANDOUT);
                mvwprintw(menu, index + offset, 1, menuItems[index].c_str());
                wattroff(menu, A_STANDOUT);
                break;
            }
            case 'S':
            case 's':
            case KEY_DOWN:
            {
                mvwprintw(menu, index + offset, 1, menuItems[index].c_str());
                index++;
                index = (index > menuItems.size() - 1) ? 0 : index;
                wattron(menu, A_STANDOUT);
                mvwprintw(menu, index + offset, 1, menuItems[index].c_str());
                wattroff(menu, A_STANDOUT);
                break;
            }
            case 'P':
            case 'p':
                // 按P键直接恢复游戏
                delwin(menu);
                return 0; // Resume
            case 'Q':
            case 'q':
                // 按Q键直接退出
                delwin(menu);
                return 1; // Quit
        }
        wrefresh(menu);
        if (key == ' ' || key == 10)
        {
            break;
        }
        simpleDelay(100);
    }
    delwin(menu);

    if (index == 0)
    {
        return 0; // Resume
    }
    else
    {
        return 1; // Quit
    }
}

bool doubleGame::isPaused() const
{
    return this->mIsPaused;
}

// 检查是否进入鏖战
void doubleGame::checkFinalFight()
{
    // 如果未启用鏖战功能，直接返回
    if (!mFinalFightEnabled)
    {
        return;
    }
    
    // 如果已经触发过鏖战，不再检查
    if (mFinalFightTriggered)
    {
        return;
    }
    
    // 检查是否到达45秒
    if (mFrameCounter - mGameStartFrame >= mFinalFightDelay)
    {
        mIsFinalFight = true;
        mFinalFightTriggered = true;
        mFinalFightDisplayCounter = 0;
    }
}

// 渲染鏖战消息
void doubleGame::renderFinalFightMessage() const
{
    if (!mIsFinalFight || mFinalFightDisplayCounter >= mFinalFightDisplayDuration)
    {
        return;
    }
    
    // 清空游戏窗口
    werase(this->mWindows[1]);
    box(this->mWindows[1], 0, 0);
    
    // 计算中心位置
    int centerX = this->mGameBoardWidth / 2;
    int centerY = this->mGameBoardHeight / 2;
    
    // 创建震撼的"FINAL FIGHT!"效果
    const char* finalFightText[] = {
        "########################################",
        "#                                      #",
        "#    FFFFF  III  N   N   AAA   L       #",
        "#    F       I   NN  N  A   A  L       #",
        "#    FFF     I   N N N  AAAAA  L       #",
        "#    F       I   N  NN  A   A  L       #",
        "#    F      III  N   N  A   A  LLLLL   #",
        "#                                      #",
        "#    FFFFF  III   GGG   H   H  TTTTT   #",
        "#    F       I   G   G  H   H    T     #",
        "#    FFF     I   G      HHHHH    T     #",
        "#    F       I   G  GG  H   H    T     #",
        "#    F      III   GGG   H   H    T     #",
        "#                                      #",
        "#                 !!!                  #",
        "#                 !!!                  #",
        "#                  !                   #",
        "#                                      #",
        "########################################"
    };
    
    int textLines = sizeof(finalFightText) / sizeof(finalFightText[0]);
    int startY = centerY - textLines / 2;
    int startX = centerX - 20; // 文本宽度约40字符，所以向左偏移20
    
    // 确保文本不会超出窗口边界
    if (startY < 1) startY = 1;
    if (startX < 1) startX = 1;
    
    // 渲染文本
    for (int i = 0; i < textLines; i++)
    {
        if (startY + i < this->mGameBoardHeight - 1)
        {
            mvwprintw(this->mWindows[1], startY + i, startX, "%s", finalFightText[i]);
        }
    }
    
    wrefresh(this->mWindows[1]);
}

// 添加新的渲染鏖战消息并闪屏的方法
void doubleGame::renderFinalFightWithFlash() const
{
    // 暂停游戏3秒并闪屏3次
    for (int flashCount = 0; flashCount < 3; flashCount++)
    {
        // 显示鏖战消息
        werase(this->mWindows[1]);
        box(this->mWindows[1], 0, 0);
        
        // 计算中心位置
        int centerX = this->mGameBoardWidth / 2;
        int centerY = this->mGameBoardHeight / 2;
        
        // 创建震撼的"FINAL FIGHT!"效果
        const char* finalFightText[] = {
            "########################################",
            "#                                      #",
            "#    FFFFF  III  N   N   AAA   L       #",
            "#    F       I   NN  N  A   A  L       #",
            "#    FFF     I   N N N  AAAAA  L       #",
            "#    F       I   N  NN  A   A  L       #",
            "#    F      III  N   N  A   A  LLLLL   #",
            "#                                      #",
            "#    FFFFF  III   GGG   H   H  TTTTT   #",
            "#    F       I   G   G  H   H    T     #",
            "#    FFF     I   G      HHHHH    T     #",
            "#    F       I   G  GG  H   H    T     #",
            "#    F      III   GGG   H   H    T     #",
            "#                                      #",
            "#                 !!!                  #",
            "#                 !!!                  #",
            "#                  !                   #",
            "#                                      #",
            "########################################"
        };
        
        int textLines = sizeof(finalFightText) / sizeof(finalFightText[0]);
        int startY = centerY - textLines / 2;
        int startX = centerX - 20; // 文本宽度约40字符，所以向左偏移20
        
        // 确保文本不会超出窗口边界
        if (startY < 1) startY = 1;
        if (startX < 1) startX = 1;
        
        // 使用闪烁和粗体效果
        wattron(this->mWindows[1], A_BOLD | A_BLINK);
        
        // 渲染文本
        for (int i = 0; i < textLines; i++)
        {
            if (startY + i < this->mGameBoardHeight - 1)
            {
                mvwprintw(this->mWindows[1], startY + i, startX, "%s", finalFightText[i]);
            }
        }
        
        wattroff(this->mWindows[1], A_BOLD | A_BLINK);
        
        wrefresh(this->mWindows[1]);
        
        // 显示500毫秒
        simpleDelay(500);
        
        // 清空屏幕制造闪烁效果
        werase(this->mWindows[1]);
        box(this->mWindows[1], 0, 0);
        wrefresh(this->mWindows[1]);
        
        // 空白显示500毫秒
        simpleDelay(500);
    }
    
    // 最后再显示一次鏖战消息
    werase(this->mWindows[1]);
    box(this->mWindows[1], 0, 0);
    
    int centerX = this->mGameBoardWidth / 2;
    int centerY = this->mGameBoardHeight / 2;
    
    const char* finalFightText[] = {
        "########################################",
        "#                                      #",
        "#    FFFFF  III  N   N   AAA   L       #",
        "#    F       I   NN  N  A   A  L       #",
        "#    FFF     I   N N N  AAAAA  L       #",
        "#    F       I   N  NN  A   A  L       #",
        "#    F      III  N   N  A   A  LLLLL   #",
        "#                                      #",
        "#    FFFFF  III   GGG   H   H  TTTTT   #",
        "#    F       I   G   G  H   H    T     #",
        "#    FFF     I   G      HHHHH    T     #",
        "#    F       I   G  GG  H   H    T     #",
        "#    F      III   GGG   H   H    T     #",
        "#                                      #",
        "#                 !!!                  #",
        "#                 !!!                  #",
        "#                  !                   #",
        "#                                      #",
        "########################################"
    };
    
    int textLines = sizeof(finalFightText) / sizeof(finalFightText[0]);
    int startY = centerY - textLines / 2;
    int startX = centerX - 20;
    
    if (startY < 1) startY = 1;
    if (startX < 1) startX = 1;
    
    wattron(this->mWindows[1], A_BOLD);
    
    for (int i = 0; i < textLines; i++)
    {
        if (startY + i < this->mGameBoardHeight - 1)
        {
            mvwprintw(this->mWindows[1], startY + i, startX, "%s", finalFightText[i]);
        }
    }
    
    wattroff(this->mWindows[1], A_BOLD);
    
    wrefresh(this->mWindows[1]);
    
    // 最后暂停1秒
    simpleDelay(1000);
}